/**
 * Created by Administrator on 2017/5/24 0024.
 */

import './style/style.scss';

class DragAndSlide {
    /*
     * >> ulquery: query selector like '#<name>' for specify the ul container
     * >> option: options {
     *                   motion: function(t) {...}           // Overwrite the motion function.
     *                   disablearea: [ [x,y], [x,y] ]       // React area where drag will be disabled.
     *                 }
     *
     * example:  var someInstance = new DragAndSlide(query);
     *           someInstance.start();                   // This well start the slide
     * */
    constructor(containerQuery, option) {
        // Initial variable
        let container = document.querySelector(containerQuery);
        this.container = container;

        let ul = container.querySelector('ul');
        ul.style.width = '100%';
        this.ul = ul;

        this.liitem = this.ul.querySelectorAll('li');
        this.viewWidth = 0;
        this.ongoingTouches = [];
        this.maxDif = 100;
        this.currentSlide = 0;
        this.inAnimation = false;
        this.touchMoved = false;

        // Optional
        if(option.motion) {
            this.specifiedMotion = option.motion;
        }
        if(option.disablearea) {
            this.disablearea = option.disablearea;
        }
    }

    /*-------------------
     * Initialize process
     * ------------------*/
    init() {
        this.viewWidth = window.innerWidth;

        // Setting containers style.
        this.ul.style.position = 'relative';
        // this.ul.style.overflow = 'hidden';
        this.ul.style.left = 0;

        this.liitem.forEach(function(item, index, list) {
            // Style settings
            item.style.position = 'absolute';
            item.style.width = this.viewWidth + 'px';
            item.style.top = 0;
            item.style.left = index * this.viewWidth + 'px';
            item.style.height = window.innerHeight + 'px';
            item.style.overflowX = 'scroll';
        }, this);
    }


    /*-------------------
     * Event handle function
     * ------------------*/
    handleStart(evt) {
        // evt.preventDefault();
        let touches = evt.changedTouches;
        for (let i=0;i<touches.length;i++) {
            this.ongoingTouches.push(this.copyTouch(touches[i]));
            this.startPoint = {
                x: touches[i].pageX,
                y: touches[i].pageY,
            };
        }
    }

    handleMove(evt) {
        // evt.preventDefault();
        let touches = evt.changedTouches;

        for (let i=0;i<touches.length;i++) {
            let idx = this.ongoingTouchIndexById(touches[i].identifier);

            // Check whether touch point is in disable area if it is then return;

            let limitXMax = Math.floor(this.viewWidth * 0.8);
            let limitXMin = Math.floor(this.viewWidth * 0.1);

            if ( this.startPoint.x > limitXMin
                && this.startPoint.x < limitXMax ) {
                return -1;
            }

            if (idx >= 0) {

                let deltaX = this.ongoingTouches[idx].pageX - touches[i].pageX;
                if (!this.inAnimation) this.shiftByPx(-deltaX);

                let deltaY = this.ongoingTouches[idx].pageY - touches[i].pageY;


                this.ongoingTouches.splice(idx, 1, this.copyTouch(touches[i]));
            }
        }
    }

    handleEnd(evt) {
        // If the move action triggered preventDefault should be called.
        if (this.touchMoved) {
            evt.preventDefault();
        }
        this.touchMoved = false;
        let touches = evt.changedTouches;

        for (let i=0;i<touches.length;i++) {
            let idx = this.ongoingTouchIndexById(touches[i].identifier);
            if (!this.inAnimation) this.posControl_II();

            if(idx >= 0) {
                this.ongoingTouches.splice(idx, 1);
            }
        }
    }
    handleCancel(evt) {
        evt.preventDefault();
        let touches = evt.changedTouches;

        for (let i=0;i<touches.length;i++) {
            let idx = this.ongoingTouchIndexById(touches[i].identifier);

            if(idx >= 0) {
                this.ongoingTouches.splice(idx, 1);
            }
        }
    }

    /*-----------------------------
     * Function for dealing with UI
     * -----------------------------*/
    shiftByPx(p) {
        // Update view.
        this.ul.style.left = parseInt(this.ul.style.left) + p + 'px';
    }

    shiftByDis(dis, currentpos) {
        this.ul.style.left = (currentpos + dis) + 'px';
    }

    // Animation
    animate(delta) {

        let motion = this.specifiedMotion;

        let time = 0,
            currentpos = parseInt(this.ul.style.left);

        // When is is animation prevent the following drag action.
        this.inAnimation = true;

        let timeloop = setInterval(() => {
            let portion = motion?motion(time):this.motion(time);
            this.shiftByDis(-delta * portion, currentpos);
            time += 0.05;
            if (time >= 1) {
                clearInterval(timeloop);
                this.inAnimation = false;
                this.ajustment();
            }
        }, 20);
    }

    motion(t) {
        return -1/2 * (Math.pow(Math.E, -6*t)) * (-2 * (Math.pow(Math.E,6*t)) + Math.sin(12*t) + 2*Math.cos(12*t));
    }

    posControl_II(index) {
        let CL = -parseInt(this.ul.style.left),  // Current position after moved.
            n = this.currentSlide,               // Current slide index
            v = this.viewWidth,                  // Viewport width
            D = CL - n* v,                       // Current position minus current slide position.
            N = this.liitem.length;

        if (index || index == 0) {
            this.animate((index-n) * v);
            if (index-n > 0) {
                this.currentSlide += index-n;
            } else {
                this.currentSlide += index-n;
            }
            return;
        }

        // If D > 0, then this motion should go to the right
        if (D > 0 && D >= this.maxDif ) {
            let ML = ( n == (N-1) )?-D:( (n+1)*v - CL );

            this.animate(ML);

            if ( !(n == (N-1)) ) {
                this.currentSlide ++;
            }

            try {
                this.moveIndicator(this.currentSlide);
            } catch(e) {
                console.log(e.toString());
            }

            return 1;
        } else if (D > 0 && D < this.maxDif) {
            this.animate(-D);
            return -1;
        }
        // If D < 0, then this motion should go to left
        if (D < 0 && Math.abs(D) >= this.maxDif) {
            let ML = ( n == 0 )?-D:( (n-1)*v - CL );

            this.animate(ML);

            if ( !(n == 0) ) {
                this.currentSlide --;
            }

            try {
                this.moveIndicator(this.currentSlide);
            } catch(e) {
                console.log(e.toString());
            }

            return 1;
        } else if (D < 0 && Math.abs(D) < this.maxDif) {
            this.animate(-D);
            return -1;
        }
    }
    ajustment() {
        let index = this.currentSlide,
            width = this.viewWidth;
        let pos = index * width;
        this.ul.style.left = (-pos) + 'px';
    }


    /*-----------------
     * Helper function
     * ----------------*/
    copyTouch(touch) {
        return {
            identifier: touch.identifier,
            pageX: touch.pageX,
            pageY: touch.pageY,
        };
    }

    ongoingTouchIndexById(idToFind) {
        /*
         * Find the ongoing touche's index in the ongoingTouches by it's identifier.
         * */
        // console.log(idToFind + '\n');
        // console.log(JSON.stringify(this.ongoingTouches));
        for (var i=0;i<this.ongoingTouches.length;i++) {
            var id = this.ongoingTouches[i].identifier;
            if(id == idToFind) {
                // console.log('touch found.');
                return i;
            }
        }
        return -1; // Not found.
    }

    /*------------------
     * Start up function
     * -----------------*/
    start() {
        this.liitem = this.ul.querySelectorAll('li');
        let self = this;
        this.ul.addEventListener('touchstart', function(evt) {
            self.handleStart(evt);
        }, false);this.ul.addEventListener('touchmove', function(evt) {
            self.handleMove(evt);
        }, false);this.ul.addEventListener('touchend', function(evt) {
            self.handleEnd(evt);
        }, false);this.ul.addEventListener('touchcancel', function(evt) {
            self.handleCancel(evt);
        }, false);

        // Update window width on screen change.
        window.onresize = () => {
            this.viewWidth = window.innerWidth;
            this.init();
        };
        this.init();
    }
}


// slide tab inherit from DragAndSlide
class SlideTab extends DragAndSlide {

    constructor(option) {
        super(option.query, option);
        this.tabcontainer = document.querySelector(option.tabquery);
        this.tabcontainer.style.position = 'relative';

        this.tabul = this.tabcontainer.querySelector('ul');
        this.tabul.style.display = 'flex';
        this.tabul.style.flexDirection = 'row';

        this.tabitem = this.tabcontainer.querySelectorAll('li');
        this.tabWidth = parseInt(this.tabcontainer.offsetWidth);

        this.tabitem.forEach((item, index) => {
            item.setAttribute('data-index', index);
            item.style.width = parseInt(this.tabWidth/this.tabitem.length) + 'px';
        });

        // Create indicator
        let indicator = document.createElement('div');
        indicator.style.position = 'absolute';
        indicator.style.left = '0px';
        indicator.style.bottom = '0px';
        indicator.style.width = parseInt(this.tabWidth/this.tabitem.length) + 'px';
        indicator.style.height = '2px';
        indicator.style.background = '#0f0';

        this.indicator = indicator;

        // append indicator to tabcontainer
        this.tabcontainer.appendChild(this.indicator);


        this.currentIndicator = 0;
        this.indInAnimation = false;
    }

    // Event handler
    handleClick(e) {
        let index = e.currentTarget.getAttribute('data-index');

        if (this.inAnimation) return;

        this.moveIndicator(index);
        this.moveSlide(index);
    }

    /*---------------------------
     * Function for dealing with UI
     * --------------------------*/
    shift(delta, currentpos) {
        this.indicator.style.left = (currentpos +  delta) + 'px';
    }

    moveIndicator(index) {
        let currentpos = parseInt(this.indicator.style.left);
        let indWidth = parseInt(this.tabWidth/this.tabitem.length);
        let delta = index * indWidth - currentpos;

        let time = 0;
        this.IndInAnimation = true;
        let timeloop = setInterval(() => {
            let portion = this.motion(time);
            this.shift(delta * portion, currentpos);
            time += 0.05;
            if (time >= 1) {
                clearInterval(timeloop);
                this.indInAnimation = false;
            }
        }, 20);
    }
    motion(t) {
        return -1/2 * (Math.pow(Math.E, -6*t)) * (-2 * (Math.pow(Math.E,6*t)) + Math.sin(12*t) + 2*Math.cos(12*t));
    }

    moveSlide(index) {
        this.posControl_II(index);
    }
    /*----------------
     * Start up
     * ----------------*/
    startSlide() {
        this.start();
        let self = this;
        this.tabitem.forEach((item, index) => {
            item.addEventListener('click', function(e) {
                self.handleClick(e);
            });
        });
    }
}
window.DragAndSlide = DragAndSlide;
// var slidtab = new SlideTab({
//     query: '.dg-contents-box',
//     tabquery:'.dg-buttons',
// });
// slidtab.startSlide();